#import "BWBackStitchDrawTool.h"
#import "BWBackStitchLayer.h"
#import "BWBackStitchChangeList.h"
#import "BWLayerView.h"
#import "BWGridGeometry.h"
#import "BWThread.h"
#import "BWColorKeyWindowController.h"
#import <BSL/BSL.h>

@implementation BWBackStitchDrawTool

- (id) initWithGeometry: (BWGridGeometry *) g
                 layers: (BWLayerSet *) l
              layerView: (BWLayerView *) lv
{
    if (self = [super initWithGeometry: g
                      layers: l
                      layerView: lv]) {

        layer = [self pickLayerForKind: kLayerKind_BackStitch];
        [layer retain];

        
        changeList = [[BWBackStitchChangeList alloc] init];
    }

    return (self);

} // initWithGeometry


- (void) dealloc
{
    [layer setChangeList: nil];
    [layer release];
    [changeList release];

    [super dealloc];

} // dealloc


- (BOOL) handleMouseDown: (NSEvent *) event
                 atPoint: (NSPoint) mouse
{
    dragging = YES;

    [changeList purge];
    [layer release];
    layer = [self pickLayerForKind: kLayerKind_BackStitch];
    [layer retain];
    [layer setChangeList: changeList];

    int row, column;
    BWGrid_Quadrant quadrant;
    [geometry getIntersectionRow: &row
              column: &column
              quadrant: &quadrant
              nearPoint: mouse];

    startRow = endRow = row;
    startColumn = endColumn = column;
    startQuadrant = endQuadrant = quadrant;

    BWThread *thread = [[BWColorKeyWindowController sharedController]
                           selectedThread];

    [changeList addBackStitchFromRow: startRow
                column: startColumn
                quadrant: startQuadrant
                toRow: endRow
                column: endColumn
                quadrant: endQuadrant
                thread: thread];

    [self invalidateRectAt: startRow
          column: startColumn
          row: endRow
          column: endColumn];

    return (YES);

} // handleMouseDown


- (void) constrainRow: (int *) row
               column: (int *) column
             quadrant: (BWGrid_Quadrant *) quadrant
{
    int rowDelta, columnDelta;
    
    rowDelta = abs (startRow - *row);
    columnDelta = abs (startColumn - *column);
    
    if (rowDelta > columnDelta) {
        // vertical line
        *column = startColumn;
        *quadrant = startQuadrant;
        
    } else if (columnDelta >= rowDelta) {  // >= to prevent diagonal line
        // horizontal line
        *row = startRow;
        *quadrant = startQuadrant;
        
    } else {
        if (startQuadrant != *quadrant) {
            *quadrant = startQuadrant;
        }
    }

} // constrainRow


- (void) handleMouseDragged: (NSEvent *) event
                    atPoint: (NSPoint) mouse
{
    int row, column;
    BWGrid_Quadrant quadrant;

    [geometry getIntersectionRow: &row
              column: &column
              quadrant: &quadrant
              nearPoint: mouse];

    BOOL constrain = ([event modifierFlags] & NSShiftKeyMask) ? YES : NO;

    if (constrain) {
        [self constrainRow: &row  column: &column  quadrant: &quadrant];
    }

    int oldEndRow = endRow;
    int oldEndColumn = endColumn;

    endRow = row;
    endColumn = column;
    endQuadrant = quadrant;

    BWThread *thread = [[BWColorKeyWindowController sharedController]
                           selectedThread];

    [changeList purge];
    [changeList addBackStitchFromRow: startRow
                column: startColumn
                quadrant: startQuadrant
                toRow: endRow
                column: endColumn
                quadrant: endQuadrant
                thread: thread];

    int r1, r2, c1, c2;
    r1 = BWMin3 (startRow, oldEndRow, endRow);
    c1 = BWMin3 (startColumn, oldEndColumn, endColumn);
    r2 = BWMax3 (startRow, oldEndRow, endRow);
    c2 = BWMax3 (startColumn, oldEndColumn, endColumn);

    [self invalidateRectAt: r1
          column: c1
          row: r2
          column: c2];

} // handleMouseDragged


- (void) handleMouseUp: (NSEvent *) event
               atPoint: (NSPoint) mouse
{
    dragging = NO;

    // don't allow just single dots
    if (startRow != endRow
        || startColumn != endColumn
        || startQuadrant != endQuadrant) {
        [layer applyChanges];
    }
    [layer setChangeList: nil];

} // handleMouseUp


- (void) handleKeyDown: (NSEvent *) event
               atPoint: (NSPoint) mouse
{
    NSString *chars = [event characters];
    unichar character = [chars characterAtIndex: 0];

    if (character == 27) {
        dragging = NO;
        [self invalidateRectAt: startRow
              column: startColumn
              row: endRow
              column: endColumn];
        [layer setChangeList: nil];
    }

} // handleKeyDown



- (void) handleFlagsChanged: (NSEvent *) event
                    atPoint: (NSPoint) mouse
{
    if (dragging) {
        [self handleMouseDragged: event
              atPoint: mouse];
    }

} // handleFlagsChanged


- (unsigned int) capabilities
{
    unsigned int capabilities = [super capabilities];
    
    capabilities |= kCapability_BackStitch;
    capabilities |= kCapability_TopLayer;
    return (capabilities);

} // capabilities



- (NSArray *) affectedLayers
{
    if (layer == nil) {
        return (nil);
    } else {
        return ([NSArray arrayWithObject: layer]);
    }

} // affectedLayers


- (NSString *) name
{
    return (@"Draw backstitches");
} // name

@end // BWBackStitchDrawTool

